세션 기반 인증

11/12/2024

세션 기반 인증이란?

세션 기반 인증은 사용자가 웹 사이트에 로그인할 때, 서버에서 세션(session)을 생성하고 이를 통해 사용자의 인증 상태를 유지하는 방식이다. 세션은 서버 측에서 관리되며, 클라이언트는 서버로부터 받은 세션 ID를 쿠키에 저장하여 이후의 요청마다 이 세션 ID를 함께 전송함으로써 인증 상태를 유지한다.

왜 필요하지?

HTTP의 특징 중 하나는 무상태(Stateless) 하다는 것이다. 그렇기에 HTTP 요청을 통해 데이터를 주고 받을 때 요청이 끝나면 요청한 사용자의 정보 등을 유지하지 않는 특징이 있다.
따라서 "로그인 상태를 어떻게 유지하는가"에 대한 의문점이 생기기 마련이다. 로그인은 이전에 로그인한 상태값이 남아 있어야 하기 때문이다. 예를 들어, 메인 페이지에서 로그인을 한 뒤 페이지를 이동했을 때 로그인이 유지되지 않고 다시 로그인 해야 한다면 매우 귀찮아질 것 이다.

동작 원리

  1. 로그인 요청: 사용자가 로그인 폼을 통해 자격 증명(예: 사용자 이름, 비밀번호)을 서버로 제출한다.
  2. 자격 증명 확인: 서버는 데이터베이스에서 사용자의 자격 증명을 확인한다.
  3. 세션 생성: 자격 증명이 유효하면 서버는 고유한 세션 ID를 생성하고, 이 세션 ID와 함께 사용자 정보를 서버 측 세션 스토리지에 저장한다.
  4. 세션 ID 전달: 서버는 클라이언트에게 세션 ID를 쿠키에 담아 전달한다.
  5. 요청 시 세션 ID 전송: 이후 클라이언트는 모든 요청에 세션 ID를 포함시켜 서버로 전송하며, 서버는 이 세션 ID를 확인하여 해당 사용자의 인증 상태를 유지한다.
  6. 세션 만료/로그아웃: 세션은 일정 시간이 지나면 만료되거나, 사용자가 명시적으로 로그아웃하면 삭제된다.

세션, 세션ID

  • 세션:
    • 세션은 사용자가 웹 사이트에 접속한 후부터 로그아웃하거나 브라우저를 닫을 때까지의 일시적인 상태 정보를 말한다.
    • 서버는 사용자의 세션을 통해 로그인 상태나 장바구니 정보 같은 사용자 고유의 데이터를 관리한다.
    • 세션 데이터는 주로 서버 측에서 관리되며, 각 사용자마다 고유한 세션이 생성된다.
  • 세션ID:
    • 세션 ID는 각 사용자의 세션을 식별하기 위한 고유한 값이다.
    • 서버는 사용자가 로그인하면 세션을 생성하고, 고유한 세션 ID를 클라이언트에게 전달한다.
    • 이 세션 ID는 주로 쿠키에 저장되며, 클라이언트가 서버에 요청할 때마다 함께 전송된다. 이를 통해 서버는 해당 클라이언트를 식별하고 그에 맞는 세션 데이터를 제공한다.

사용 사례

사용자가 쇼핑몰에 로그인한 후, 페이지 간 이동 시에도 로그인이 유지된다. 이는 각 요청마다 클라이언트가 쿠키에 저장된 세션 ID를 서버로 보내기 때문에 가능하다.

대부분의 전통적인 웹 애플리케이션에서 널리 사용된다. 예를 들어:

  • 쇼핑몰 사이트에서 로그인 상태 유지
  • 포럼이나 블로그 같은 웹 애플리케이션

세션 인증의 장단점

세션 기반 인증의 장점

  1. 단순성: 구현이 비교적 간단하며, 많은 웹 프레임워크에서 기본적으로 지원하는 기능이다.
  2. 서버 제어: 세션은 서버 측에서 관리되므로, 서버가 언제든지 특정 세션을 무효화하거나 만료 시킬 수 있다.
  3. 복잡한 권한 관리 가능: 세션을 통해 사용자 정보뿐만 아니라 권한 정보도 저장할 수 있어, 복잡한 권한 관리가 가능하다.

세션 기반 인증의 단점

  1. 서버 부하: 모든 사용자에 대한 세션 정보를 서버가 유지해야 하므로, 많은 사용자가 접속할 경우 서버의 메모리나 스토리지 자원이 많이 소모될 수 있다.
  2. 확장성 문제: 세션이 서버에 저장되기 때문에, 여러 대의 서버에서 동일한 세션 정보를 공유하려면 추가적인 설정(예: 세션 클러스터링)이 필요하다.
  3. 보안 취약점: 세션 ID가 탈취되면 공격자가 해당 사용자의 권한을 가질 수 있다. 이를 방지하기 위해 HTTPS를 사용하고, HttpOnly, Secure, SameSite 속성을 설정하여 보안을 강화해야 한다.

보안 고려 사항

  • HTTPS 사용: 세션 ID가 네트워크 상에서 탈취되지 않도록 HTTPS를 통해 암호화된 통신을 해야 한다.
  • 쿠키 설정 강화:
    • HttpOnly: 자바스크립트 쿠키에 접근하지 못하게 하여 XSS(크로스 사이트 스크립팅) 공격을 방지한다.
    • Secure: HTTPS 연결에서만 쿠키가 전송되도록 설정한다.
    • SameSite: CSRF(크로스 사이트 요청 위조) 공격을 방지하기 위해 쿠키가 동일 사이트 내에서만 전송되도록 설정한다.
  • 세션 만료 시간 설정: 일정 시간 동안 활동이 없으면 자동으로 세션이 만료되도록 설정하여 보안을 강화할 수 있다.

다른 인증 방식과 비교

특성

세션 기반 인증(Session-Based Authentication)

토큰 기반 인증(Token-Based Authentication)

저장 위치

서버 측 (세션 스토리지)

클라이언트 측 (JWT 등 토큰 자체에 정보 포함)

확장성

낮음 (서버 상태 유지 필요)

높음 (서버 상태 불필요)

보안성

적절한 설정 시 안전함

토큰 탈취 시 위험 (하지만 서명 검증 가능)

복잡도

상대적으로 간단

상대적으로 복잡 (토큰 발급 및 검증 필요)


코드 예시

초기화 및 설정

npm init -y
npm install express express-session body-parser
  • 'npm init' 명령어로 새로운 Node.js 프로젝트 초기화
  • 필요한 패키지 설치
    • express: Node.js에서 서버를 쉽게 구축할 수 있는 프레임워크
    • express-session: 세션 관리를 위한 미들웨어
    • body-parser: POST 요청에서 보낸 데이터를 파싱하기 위한 미들웨어

서버 코드(app.js)

const express = require('express'); 
const session = require('express-session'); 
const bodyParser = require('body-parser'); 

const app = express(); 

// Body parser 설정 (POST 요청 데이터 파싱) 
app.use(bodyParser.urlencoded({ extended: true })); 

// 세션 설정 
app.use(session({ 
	secret: 'mySecretKey', // 세션을 암호화하기 위한 키 
	resave: false, // 세션이 수정되지 않아도 다시 저장할지 여부 
	saveUninitialized: true, // 초기화되지 않은 세션도 저장할지 여부 
	cookie: { secure: false } // HTTPS가 아닌 경우에도 쿠키를 사용할 수 있도록 설정 
})); 

// 간단한 사용자 데이터베이스 (예시) 
const users = { 
	'user1': 'password1', 
	'user2': 'password2' 
}; 

// 로그인 페이지 
app.get('/login', (req, res) => { 
	res.send(` 
		<h2>로그인</h2> 
		<form method="POST" action="/login"> 
			<label>사용자 이름:</label> 
			<input type="text" name="username" /> 
			<label>비밀번호:</label> 
			<input type="password" name="password" /> 
			<button type="submit">로그인</button> 
		</form> 
	`); 
}); 

// 로그인 처리 
app.post('/login', (req, res) => { 
	const { username, password } = req.body; 
	
	// 사용자 인증 확인 
	if (users[username] && users[username] === password) {
		req.session.user = username; // 세션에 사용자 정보 저장
		res.redirect('/dashboard'); 
	} else { 
		res.send('로그인 실패! 사용자 이름 또는 비밀번호가 잘못되었습니다.'); 
	} 
}); 

// 대시보드 페이지 (로그인된 사용자만 접근 가능) 
app.get('/dashboard', (req, res) => { 
	if (req.session.user) { 
		res.send(`<h2>환영합니다, ${req.session.user}님!</h2><a href="/logout">로그아웃</a>`); 
		} else { res.send('로그인되지 않았습니다. <a href="/login">로그인 페이지로 이동</a>'); 
	} 
}); 

// 로그아웃 처리 
app.get('/logout', (req, res) => { 
	req.session.destroy(); // 세션 삭제 
	res.send('로그아웃 되었습니다. <a href="/login">다시 로그인</a>'); 
}); 

// 서버 실행 
app.listen(3000, () => { 
	console.log('서버가 http://localhost:3000 에서 실행 중입니다.'); 
});

부분 설명

세션 설정

app.use(session({ 
	secret: 'mySecretKey', 
	resave: false, 
	saveUninitialized: true, 
	cookie: { secure: false } 
}));
  • secret: 세션을 암호화하기 위한 키이다.
  • resave: 세션이 수정되지 않아도 매번 저장할지 여부를 설정한다.
  • saveUninitialized: 초기화되지 않은 세션도 저장할지 여부를 설정한다.
  • cookie.sccure: HTTPS 환경에서만 쿠키를 전송할지 설정한다. 개발 환경에서는 'false'로 설정한다.

로그인 처리

app.post('/login', (req, res) => { 
	const { username, password } = req.body; 
	
	// 사용자 인증 확인 
	if (users[username] && users[username] === password) {
		req.session.user = username; // 세션에 사용자 정보 저장
		res.redirect('/dashboard'); 
	} else { 
		res.send('로그인 실패! 사용자 이름 또는 비밀번호가 잘못되었습니다.'); 
	} 
});
  • 사용자가 로그인 폼을 제출하면 서버는 해당 자격 증명을 확인하고, 성공하면 세션에 사용자 정보를 저장한다.

대시보드 접근 제어

app.get('/dashboard', (req, res) => { 
	if (req.session.user) { 
		res.send(`<h2>환영합니다, ${req.session.user}님!</h2><a href="/logout">로그아웃</a>`); 
		} else { res.send('로그인되지 않았습니다. <a href="/login">로그인 페이지로 이동</a>'); 
	} 
});
  • 사용자가 대시보드에 접근할 때마다 세션에 저장된 'user' 정보를 확인하여 로그인 여부를 판단한다.

로그아웃 처리

app.get('/logout', (req, res) => { 
	req.session.destroy(); // 세션 삭제 
	res.send('로그아웃 되었습니다. <a href="/login">다시 로그인</a>'); 
});
  • 사용자가 로그아웃하면 서버에서 해당 사용자의 세션을 삭제하고 로그아웃 상태로 만든다.

실행

node app.js
  1. 브라우저에서 'http://localhost:3000/login' 으로 접속하여 로그인 페이지로 이동한다.
  2. 제공된 사용자 목록 중 하나(예: 'user1', 'password1')로 로그인한다.
  3. 로그인에 성공하면 대시보드 페이지로 리디렉션된다.
  4. 로그아웃 링크를 클릭하면 로그아웃되고 다시 로그인 페이지로 돌아간다.

블로그 내 관련 문서


참고 자료

출처 :

댓글을 불러오는 중...